package com.nexgo.payment.action.readcard;

import android.os.Handler;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.text.TextUtils;

import com.nexgo.lamp.LampOperate;
import com.nexgo.oaf.apiv3.SdkResult;
import com.nexgo.oaf.apiv3.device.reader.CardInfoEntity;
import com.nexgo.oaf.apiv3.device.reader.CardReader;
import com.nexgo.oaf.apiv3.device.reader.CardSlotTypeEnum;
import com.nexgo.oaf.apiv3.device.reader.OnCardInfoListener;
import com.nexgo.payment.api.ApiDeviceEngine;
import com.nexgo.payment.constrant.CardMode;
import com.nexgo.payment.constrant.PreferencesConstants;
import com.nexgo.payment.constrant.SysConstant;
import com.nexgo.payment.constrant.TransType;
import com.nexgo.payment.databases.DataSource;
import com.nexgo.payment.entity.CardInfo;
import com.nexgo.payment.entity.TransData;
import com.nexgo.sound.SoundManager;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashSet;

import java8.util.Optional;

import static com.google.common.base.Preconditions.checkNotNull;

/**
 * Created by xiaox on 2017/7/6.
 */

public class ReadCardPresenter implements ReadCardContract.Presenter {
    private Logger mLog = LoggerFactory.getLogger(ReadCardPresenter.class.getSimpleName());

    private final ReadCardContract.View mView;
    private final DataSource mRepository;
    private final TransData mTransData;
    private final Handler mHandler;
    private final CardReader mSdkCardReader;
    private boolean mIsRunning;
    private boolean mIsReadCardComplete = false;
    private final SoundManager mSoundManager;

    public ReadCardPresenter(@NonNull ReadCardContract.View view, @NonNull DataSource repository, @NonNull TransData transData) {
        mView = checkNotNull(view);
        mRepository = checkNotNull(repository);
        mTransData = checkNotNull(transData);
        view.setPresenter(this);
        mHandler = new Handler(Looper.getMainLooper());
        mSdkCardReader = ApiDeviceEngine.getInstance().getCardReader();
        mSoundManager = new SoundManager();
    }

    @Override
    public void start() {
        if (!mIsReadCardComplete) {
            mLog.debug("开启寻卡");
            mSoundManager.play(SoundManager.Type.SWIPE_CARD);
            startSearchCard();
        }
    }

    @Override
    public void pause() {

    }

    /**
     * 设置寻卡方式
     */
    private void startSearchCard() {
        System.out.println("-----设置寻卡方式-----");
        if (!TextUtils.isEmpty(mTransData.getAmount())) {
            postMainThread(() -> mView.showAmount(mTransData.getAmount()));
        }
        boolean isSupportManual = false, isSupportSwipe = false, isSupportInsert = false, isSupportTap = false;
        if (mTransData.isFallback()) {
            postMainThread(() -> mView.showUseMag());
            isSupportSwipe = true;
        } else {
            TransType transType = mTransData.getTransType();
            switch (transType) {
                case SALE:
                    //消费交易的用卡模式
                    isSupportInsert = true;
                    isSupportTap = true;
                    isSupportSwipe = true;
                    if ("1".equals(mRepository.getParamValue(PreferencesConstants.PRIORITY_TO_USE_RF))) {
                        isSupportInsert = false;
                    }
                    break;
                case EC_SALE:
                    //电子现金交易的用卡模式
                    isSupportInsert = true;
                    break;
                case EC_LOG:
                case EC_BALANCE:
                    isSupportTap = true;
                    isSupportInsert = true;
                    break;
                case AUTH:
                    //预授权交易的用卡摸式
                    isSupportInsert = true;
                    isSupportSwipe = true;
                    isSupportTap = true;
                    break;
                case AUTH_CM:
                case AUTH_CM_NOTIFY:
                case AUTH_VOID:
                case AUTH_CM_VOID:
                    isSupportInsert = true;
                    isSupportSwipe = true;
                    isSupportTap = true;
                    isSupportManual = "1".equals(mRepository.getParamValue(PreferencesConstants.ALLOW_MANUAL_PAN));
                    break;
                default:
                    isSupportInsert = true;
                    isSupportSwipe = true;
                    isSupportTap = true;
                    break;
            }
            //指定刷卡方式不为空
            if (!TextUtils.isEmpty(mTransData.getTemporary())) {
                CardMode cardMode = CardMode.valueOf(mTransData.getTemporary());
                isSupportInsert = false;
                isSupportTap = false;
                isSupportManual = false;
                isSupportSwipe = false;
                switch (cardMode) {
                    case MANUAL:
                        isSupportManual = true;
                        break;
                    case SWIPE:
                        isSupportSwipe = true;
                        break;
                    case INSERT:
                        isSupportInsert = true;
                        break;
                    case TAP:
                        isSupportTap = true;
                        break;
                    default:
                        isSupportSwipe = true;
                        break;
                }
            }
        }
        searchCard(isSupportManual, isSupportSwipe, isSupportInsert, isSupportTap);
    }

    /**
     * 开始寻卡
     *
     * @param isSupportManual 手输
     * @param isSupportSwipe  刷卡
     * @param isSupportInsert 插卡
     * @param isSupportTap    挥卡
     */
    private void searchCard(boolean isSupportManual, boolean isSupportSwipe, boolean isSupportInsert, boolean isSupportTap) {
        System.out.println("-----------开始寻卡---------");
        HashSet<CardSlotTypeEnum> slot = new HashSet<>();
        if (isSupportSwipe) {
            slot.add(CardSlotTypeEnum.SWIPE);
        }
        if (isSupportInsert) {
            slot.add(CardSlotTypeEnum.ICC1);
        }
        if (isSupportTap) {
            slot.add(CardSlotTypeEnum.RF);
        }
        if (isSupportTap) {
            LampOperate.getInstance().transActiveCard();
        }else{
            LampOperate.getInstance().closeAll();
        }
        int ret = mSdkCardReader.searchCard(slot, SysConstant.TIME_OUT_60, mCardInfoListener);
        System.out.println("----------寻卡结束，继续往下走，同事寻卡回调----------");
        if (ret == SdkResult.Success) {
            System.out.println("----------寻卡成功----------");
            mIsRunning = true;
            postMainThread(() -> mView.showCountTime(SysConstant.TIME_OUT_60));
            postMainThread(() -> mView.showReadCard(isSupportManual, isSupportSwipe, isSupportInsert, isSupportTap));
        } else {
            System.out.println("----------寻卡失败----------");
            postMainThread(() -> mView.showReadCardError());
        }
    }

    @Override
    public void destroy() {
        mSoundManager.stop();
        if (mIsRunning) {
            mSdkCardReader.stopSearch();
        }
    }

    @Override
    public void importManualPan(String pan, String expDate) {
        if (!TextUtils.isEmpty(expDate)){
            if (expDate.length() != 4 || !verifyDate(expDate)){
                postMainThread(() -> mView.showExpDateFormatError());
                return;
            }
        }
        CardInfo info = new CardInfo();
        info.setCardMode(CardMode.MANUAL);
        String cardNo = pan.replace(" ", "");
        if (cardNo.length() < 14 || cardNo.length() > 19){
            postMainThread(() -> mView.showInputCardNoError());
            return;
        }
        info.setPan(cardNo);
        info.setExpiredDate(expDate);
        postMainThread(() -> mView.showSuccessful(info));
    }

    @Override
    public void stopReadCard() {
        if (mIsRunning) {
            mSdkCardReader.stopSearch();
        }
    }

    /**
     * 判断输入有效日期是否正确
     *
     * @param expDate
     * @return
     */
    private boolean verifyDate(String expDate){
        return Optional.ofNullable(expDate)
                .filter(s -> s.length() == 4)
                .map(s -> {
                    int month = Integer.parseInt(s.substring(s.length() - 2));
                    return month > 0 && month < 13;
                }).get();
    }

    private void postMainThread(Runnable runnable) {
        if (mView.isActive()) {
            if (Looper.myLooper() == Looper.getMainLooper()) {
                runnable.run();
            } else {
                mHandler.post(runnable);
            }
        }
    }

    /**
     * 读卡回调
     */
    private OnCardInfoListener mCardInfoListener = new OnCardInfoListener() {
        @Override
        public void onCardInfo(int retCode, CardInfoEntity cardInfo) {
            mIsReadCardComplete = true;
            mIsRunning = false;
            switch (retCode) {
                case SdkResult.Success:
                    CardInfo info = new CardInfo();
                    switch (cardInfo.getCardExistslot()) {
                        case SWIPE:
                            //有IC卡芯片，不是降级交易，要求使用IC卡芯片
                            if (cardInfo.isICC() && !mTransData.isFallback()) {
                                postMainThread(() -> mView.showUseICC());
                                searchCard(false, false, true, true);
                                return;
                            }
                            //无2磁道数据
                            if (TextUtils.isEmpty(cardInfo.getTk2())) {
                                postMainThread(() -> mView.showSwipeError());
                                startSearchCard();
                                return;
                            }
                            //校验磁道数据格式，防止伪卡
                            if (cardInfo.getTk2().length() > 40 || (!TextUtils.isEmpty(cardInfo.getTk3()) && cardInfo.getTk3().length() > 107)){
                                postMainThread(() -> mView.showSwipeError());
                                startSearchCard();
                                return;
                            }
                            if ((cardInfo.getTk2().indexOf("=") < 0) && (cardInfo.getTk2().indexOf("D") < 0)){
                                postMainThread(() -> mView.showSwipeError());
                                startSearchCard();
                                return;
                            }
                            info.setCardMode(CardMode.SWIPE);
                            info.setPan(cardInfo.getCardNo());
                            info.setTk1(cardInfo.getTk1());
                            info.setTk2(cardInfo.getTk2());
                            info.setTk3(cardInfo.getTk3());
                            info.setTk1Valid(cardInfo.isTk1Valid());
                            info.setTk2Valid(cardInfo.isTk2Valid());
                            info.setTk3Valid(cardInfo.isTk3Valid());
                            info.setExpiredDate(cardInfo.getExpiredDate());
                            info.setServiceCode(cardInfo.getServiceCode());
                            postMainThread(() -> mView.showSuccessful(info));
                            break;
                        case ICC1:
                        case ICC2:
                        case ICC3:
                        case PSAM1:
                        case PSAM2:
                        case PSAM3:
                            info.setCardMode(CardMode.INSERT);
                            postMainThread(() -> mView.showSuccessful(info));
                            break;
                        case RF:
                            info.setCardMode(CardMode.TAP);
                            /*//判断交易金额是否大于等于DF20(57120)
                            float transAmt = Float.parseFloat(StringUtils.formatAmount(mTransData.getAmount(), SysConstant.FUND_DIGITS));
                            if (transAmt >= Float.parseFloat("57120")){
                                postMainThread(() -> mView.showTryOtherCommunication());
                                return;
                            }*/
                            postMainThread(() -> mView.showSuccessful(info));
                            break;
                        default:
                            break;
                    }
                    break;
                case SdkResult.TimeOut:
                    postMainThread(() -> mView.showReadCardTimeout());
                    break;
                default:
                    postMainThread(() -> mView.showReadCardError());
                    break;
            }
        }

        @Override
        public void onSwipeIncorrect() {
            postMainThread(() -> mView.showSwipeError());
        }

        @Override
        public void onMultipleCards() {
            postMainThread(() -> mView.showMultipleCards());
        }
    };
}
